package com.qianfeng.android.baoman.util;

import android.content.Context;
import android.os.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by maxiaoyu on 2015/2/6.
 * User:Maxiaoyu
 * Date:2015/2/6
 * Email:731436452@qq.com
 */
public class FileCache {
    private static FileCache ourInstance = null;

    /**
     * 这个方法必须在getInstance之前调用，主要用于初始化Android中特有的Context和
     * 私有缓存目录的功能
     *
     * @param context
     * @return
     */
    public static FileCache createInstance(Context context) {
        if (ourInstance == null) {
            ourInstance = new FileCache(context);
        }
        return ourInstance;
    }

    public static FileCache getInstance() {
        //快捷键lazy
        if (ourInstance == null) {
            throw new IllegalStateException("FileCache must invoke createInstance(Context) before getInstance()");
        }
        return ourInstance;
    }

    //Android 上下文Context
    private Context context;
    /**
     * 当前文件的缓存的目录，主要针对网址上的资源，下载到本地的情况
     */
    private File fileCacheDir;

    /**
     * 在私有的构造方法中传递参数，那么这个构造方法必须有当前类进行
     * 初始化，那么必须在静态方法中调用。
     *
     * @param context
     */
    private FileCache(Context context) {
        this.context = context;
        if (context != null) {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                //SD 卡存在
                fileCacheDir = context.getExternalCacheDir();
            } else {
                fileCacheDir = context.getCacheDir();
            }
        } else {
            //上下文没有的情况，只能自己用SD卡存储，一个自定义的目录里了
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                File directory = Environment.getExternalStorageDirectory();
                fileCacheDir = new File(directory, ".youshare");
            } else {
                throw new IllegalArgumentException("FileCache must set context or device has a sd card");
            }
        }

        if (fileCacheDir != null) {
            if (!fileCacheDir.exists()) {
                fileCacheDir.mkdir();
            }
        } else {
            throw new IllegalArgumentException("FileCache can not get a cache dir.");
        }
    }

    /**
     * @param url
     * @param data
     */
    public void putContent(String url, byte[] data) {
        if (url != null && data != null) {
            //url->文件名，映射
            String fileName = mapUrlToFile(url);
            File targetFile=new File(fileCacheDir,fileName);
            //如果文件不存在，必须通过createNewFile 然后才可以写文件
            boolean bok=true;
            if(!targetFile.exists()){

                try {
                    bok=targetFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //电表文件是否存在
            if(bok){
                FileOutputStream fout=null;
                try {
                    fout=new FileOutputStream(targetFile);
                    fout.write(data);
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    StreamUtil.close(fout);
                }
            }
        }
    }

    /**
     * 获取url 代表的数据，从本地存储中，如果有本地文件，那么返回有效，否则返回null
     *
     * @param url
     * @return
     */
    public byte[] getContent(String url) {
        byte[] ret = null;
        if (ret != null) {
            //TODO URL 中通常包含了一些不能作为文件名的字符，这种情况下要做一些映射，
            // 将url转变为唯一的，可以作为文件名存在的字符串
            //接触一个叫做MD5的消息摘要的算法
            String fileName = mapUrlToFile(url);
            if (fileName.length() > 0) {
                File targetFile = new File(fileCacheDir, fileName);
                if (targetFile.exists()) {
                    //读取字节数组到文件
                    FileInputStream fil = null;
                    try {
                        fil = new FileInputStream(targetFile);
                        ret = StreamUtil.readStream(fil);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        StreamUtil.close(fil);
                        fil=null;
                    }
                }
            }
        }
        return ret;
    }

    /**
     * 将URl转变为文件名
     */
    private static String mapUrlToFile(String url) {
        String ret = null;
        if (url != null) {
            //TODO 将url进行MD5 消息摘要
            //MD5 将任何一个内容转变为不可逆的，唯一的一个字节数组
            byte[] md5 = md5(url.getBytes());
            ret = hex(md5);
        }

        return ret;
    }

    /**
     * MD5算发将字节数组转化为唯一的字节数组的信息。
     *
     * @param data
     * @return
     */
    private static byte[] md5(byte[] data) {
        byte[] ret = null;
        if (data != null && data.length > 0) {
            try {
                MessageDigest digest = MessageDigest.getInstance("MD5");
                ret = digest.digest(data);//将data进行消息摘要，生成一个特定的字节数组，当中的数值全球唯一
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 将字节数组中每一个字节转化为0-9 a-f 这些可以显示的十六进制的数值
     *
     * @param data
     * @return
     */
    private static String hex(byte[] data) {
        StringBuilder sb = new StringBuilder();
        if (data != null && data.length > 0) {
            for (byte b : data) {
                int h, l;
                h = (b >> 4) & 0x0f;
                l = b & 0x0f;
                sb.append(Integer.toHexString(h));
                sb.append(Integer.toHexString(l));
            }
        }
        return sb.toString();
    }
}
